package com.cskaoyan.javase.basic._5extra;

/**
 * 浮点数的精度问题
 * 浮点数之所以存在精度问题,主要原因就是IEEE754标准设计下的浮点数自身问题
 * 有效位数是有限的,所以存在精度问题
 * double: 有效位数是16~17
 * float: 有效位数是7~8
 *
 * 除了以上浮点数自身的设计问题外,浮点数的精度问题还和二进制小数的自身特点有关
 * 二进制小数和十进制小数一样,都存在循环的情况,而由于计算机内存必然是有限的,(浮点数)有限的空间必然无法表示无限的小数,必然会有精度丢失的情况
 *
 * 十进制小数如何转换成二进制小数?
 * 十进制正小数（0.开头）转换成二进制，先用小数部分乘以2，取结果的整数部分(必然是1或者0)，
 * 然后小数部分继续乘2
 * 直到小数部分为0，或者已经达到了最大的位数
 * 最终的结果（0.开头）正序排列
 *
 * 以十进制小数0.1为例子:
 * 0.1 * 2 = 0.2 --> 0
 * 0.2 * 2 = 0.4 --> 0
 * 0.4 * 2 = 0.8 --> 0
 * 0.8 * 2 = 1.6 --> 1
 * 0.6 * 2 = 1.2 --> 1
 * 0.2 * 2 = 0.4 --> 0
 * 0.4 * 2 = 0.8 --> 0
 * ....
 * 以上过程显然是结束不了的,只能靠最大位数来限制,来结束,这时计算机内存中表示的小数就不再是原先的小数了,出现了精度丢失(IEEE754标准下的浮点数)
 *
 * 综上所述,double和float这种浮点数都是不适合用来计算需要精确的运算的场景
 *
 * @since 10:54
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // 0.1是一个小数的字面值常量,它默认当成double处理,当然也可以加F当float处理,那么问题来了: double的0.1和float的0.1是相等的吗?
        double a = 0.1;
        float b = 0.1F;
        // 双等号连接数值类型,就比较数值大小,结果是false
        System.out.println(a == b);
        double c = 1 - 0.9;
        float d = 1 - 0.9F;
        System.out.println(c);
        System.out.println(d);

        float a2 = 0.1F;
        // 中间18个0
        float b2 = 0.10000000000000000001F;
        System.out.println(a2 == b2);

        // 整数的字面值常量默认当int处理,以下代码相当于将int赋值给long,为什么没有报错呢?
        long num1 = 100;

        // 小数的字面值常量默认当double处理,以下代码相当于将double赋值给float,为什么报错呢?
        // float num2 = 0.1;
        // 以上区别,根本原因在于基本数据类型的类型转换机制
    }
}
